/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_gears.h"

static 	int 	_gTraceLvl_Gears = TRACELVL_WARNING;

/* 	Based on the Linux's JHash. (Lookup3()).
**	Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
**	http://burtleburtle.net/bob/
*/
#define __yrot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))

/* __yhash_mix - mix 3 32-bit values reversibly. */
#define __yhash_mix(a,b,c) \
{ \
	a -= c;  a ^= __yrot(c, 4);  c += b; \
	b -= a;  b ^= __yrot(a, 6);  a += c; \
	c -= b;  c ^= __yrot(b, 8);  b += a; \
	a -= c;  a ^= __yrot(c,16);  c += b; \
	b -= a;  b ^= __yrot(a,19);  a += c; \
	c -= b;  c ^= __yrot(b, 4);  b += a; \
}

/* __yhash_final - final mixing of 3 32-bit values (a,b,c) into c */
#define __yhash_final(a,b,c) \
{ \
	c ^= b; c -= __yrot(b,14); \
	a ^= c; a -= __yrot(c,11); \
	b ^= a; b -= __yrot(a,25); \
	c ^= b; c -= __yrot(b,16); \
	a ^= c; a -= __yrot(c,4);  \
	b ^= a; b -= __yrot(a,14); \
	c ^= b; c -= __yrot(b,24); \
}

/* The golden ration: an arbitrary value */
#if 0
#define YHASH_GOLDEN_RATIO	0x9e3779b9
#else
#define YHASH_GOLDEN_RATIO	0xdeadbeef
#endif

/* A special ultra-optimized versions that knows they are hashing exactly 3, 2 or 1 word(s). */
static 	__inline 	unsigned int _Ak_YHash_W3(unsigned int a, unsigned int b, unsigned int c, unsigned int seed)
{
	#if 1
	a += YHASH_GOLDEN_RATIO + seed;
	b += YHASH_GOLDEN_RATIO + seed;
	c += YHASH_GOLDEN_RATIO + seed;
	#else
	a += YHASH_GOLDEN_RATIO;
	b += YHASH_GOLDEN_RATIO;
	c += YHASH_GOLDEN_RATIO;
	
	#endif

	__yhash_final(a, b, c);
	return c;
}

static 	__inline 	unsigned int _Ak_YHash_W2(unsigned int a, unsigned int b, unsigned int seed)
{
	return _Ak_YHash_W3(0, a, b, seed);
}

static 	__inline 	unsigned int _Ak_YHash_W1(unsigned int a, unsigned int seed)
{
	return _Ak_YHash_W3(0, 0, a, seed);
}

/* The most generic version, hashes an arbitrary sequence
* of bytes.  No alignment or length assumptions are made about
* the input key. The result depends on endianness.
*/
static 	__inline 	void 	_Ak_YHashS(	const void 	*	key, 	unsigned int 	length, 
										unsigned int* 	seedC, 	unsigned int * 	seedB)
{
	unsigned int 		a,b,c;
	#define __YHASH_F32
	#ifdef 	__YHASH_F32
	unsigned char 		*k;
	unsigned int 		*k32= (unsigned int  *)key;
	#else
	const unsigned char *k 	= (unsigned char *)key;
	#endif

	/* Set up the internal state */
	#if 1
	a = b = c = YHASH_GOLDEN_RATIO + length + *seedC;
	c += *seedB;
	#else
	a = b = c = YHASH_GOLDEN_RATIO + length;
	#endif

	/* all but the last block: affect some 32 bits of (a,b,c) */
	while (length > 12) {
		#ifdef __YHASH_F32
		c 	+= k32[2];
		b	+= k32[1];
		a 	+= k32[0];
		k32 += 3;
		#else
		a 	+= (k[0] + ((unsigned int)k[1]<<8) + ((unsigned int)k[2]<<16) + ((unsigned int)k[3]<<24));
		b 	+= (k[4] + ((unsigned int)k[5]<<8) + ((unsigned int)k[6]<<16) + ((unsigned int)k[7]<<24));
		c 	+= (k[8] + ((unsigned int)k[9]<<8) + ((unsigned int)k[10]<<16) + ((unsigned int)k[11]<<24));
		k 	+= 12;
		#endif
		__yhash_mix(a, b, c);
		length -= 12;		
	}

	#ifdef __YHASH_F32
		k = (unsigned char *)k32;
	#endif
	
	
	/* last block: affect all 32 bits of (c), all the case statements fall through */
	switch (length) {
		case 12: c += ((unsigned int)k[11]<<24);
		case 11: c += ((unsigned int)k[10]<<16);
		case 10: c += ((unsigned int)k[9]<<8);
		case 9 : c += k[8];
		case 8 : b += ((unsigned int)k[7]<<24);
		case 7 : b += ((unsigned int)k[6]<<16);
		case 6 : b += ((unsigned int)k[5]<<8);
		case 5 : b += k[4];
		case 4 : a += ((unsigned int)k[3]<<24);
		case 3 : a += ((unsigned int)k[2]<<16);
		case 2 : a += ((unsigned int)k[1]<<8);
		case 1 : a += k[0];
			__yhash_final(a, b, c);
		case 0 :
		break;
	}
	*seedC = c;
	*seedB = b;
	return;
}

static 	__inline 	void 	_Ak_YHashS_32(	const unsigned int* key, 	unsigned int 	length, 
											unsigned int 	*	seedC,	unsigned int *	seedB)
{
	unsigned int 	a, b, c;

	/* Set up the internal state */
#if 1
	a = b = c = YHASH_GOLDEN_RATIO + (length<<2) + *seedC;
	c += *seedB;
#else
	a = b = c = YHASH_GOLDEN_RATIO + (length<<2);
#endif

	/* handle most of the key */
	while (length > 6) {
		c 	+= key[2];
		b 	+= key[1];
		a 	+= key[0];
		__yhash_mix(a, b, c);

		b 	+= key[4];
		a 	+= key[3];
		c 	+= key[5];
		key += 6;
		__yhash_mix(a, b, c);
		length -= 6;
	}
	if (length > 3){
		a 	+= key[0];
		c 	+= key[2];
		b 	+= key[1];
		key += 3;
		__yhash_mix(a, b, c);
		length -= 3;
	}

	/* handle the last 3 unsigned int's */
	/* all the case statements fall through */ 
	switch (length) {
		case 3: c += key[2];
		case 2: b += key[1];
		case 1: a += key[0];
			__yhash_final(a, b, c);
		case 0:     /* case 0: nothing left to add */
			break;
	}

	*seedC = c;
	*seedB = b;
	return;
}


/* -----------------------------------------------------------------------------
** 	Ak-Lib's Hash Function Implemention: 
*/
unsigned int 	_Ak_YHash(const void *key, unsigned int length)
{
	unsigned int 	seedC = 0;
	unsigned int 	seedB = 0;
	_Ak_YHashS(key, length, &seedC, &seedB);
	return seedC;
}

unsigned int 	_Ak_YHash32(const unsigned int *key, unsigned int length)
{
	unsigned int 	seedC = 0;
	unsigned int 	seedB = 0;
	_Ak_YHashS_32(key, length, &seedC, &seedB);
	return seedC;
}


/* -----------------------------------------------------------------------
** 	Basic String Filter:
**
*/
static 	char 		_gStrFilter_Head[]={
	'.','/', '\\', ' ', '\t' 
};

static 	char 		_gStrFilter_Ill[]={
	'`', '~', '!', '@', '#', '$', '%', '^', '&', '*',
	'-', '+', '=', '|', ':', ';', '"', ',', 
	/* '?',  */
	'<', '>', '(', ')', '{', '}', '[', ']' 
};

static 	int 	_SStrJ_Head(char * name)
{
	int 	i, count;

	count = _N_ARRAY(_gStrFilter_Head);
	for(i=0; i<count; i++){
		if(strchr(name, _gStrFilter_Head[i])){
			return -1;
		}
	}
	return 0;
}

static 	int 	_SStrJ_iLL(char * name)
{
	int 	i, count;

	count = _N_ARRAY(_gStrFilter_Ill);
	for(i=0; i<count; i++){
		if(strchr(name, _gStrFilter_Ill[i])){
			return -1;
		}
	}
	return 0;
}

#define 	_StrJ_Head_Delimit(varI, varLen, varPath, varFlag) 	\
do{\
	varI = varFlag = 0; 	\
	while(varI < varLen){	\
		if((*(varPath) == '/') || (*(varPath) == '\\')){\
			varFlag = 1; varI++, varPath++;\
		}else{\
			break;\
		}\
	}\
	varLen -= varI;\
}while(0)

#define 	_StrJ_Tail_Delimit(varI, varLen, varPath, varFlag) 	\
		do{\
			varI = varFlag = 0; 	\
			while(varI < varLen){	\
				if((*(varPath) == '/') || (*(varPath) == '\\')){\
					varFlag = 1; varI++, varPath--;\
				}else{\
					break;\
				}\
			}\
			varLen -= varI;\
		}while(0)

static 	char * 	_SStrJ_Seg(char * path, int * pSegLen)
{
	int i, length, flag;
	char * pPos;
	
	if(!path || (*path == '\0')){
		*pSegLen = -1;
		return NULL;
	}

	/* Check the Leading / */
	length = strlen(path);
	_StrJ_Head_Delimit(i, length, path, flag);
	if(length == 0){
		*pSegLen = 0;
		return NULL;
	}

	/* Check the Next / */
	pPos = strchr(path, '/');
	if(pPos == NULL){
		pPos = strchr(path, '\\');
	}
	if(pPos == NULL){
		*pSegLen = strlen(path);
		return path;
	}
	else{
		*pSegLen = pPos - path;
		return path;
	}
	return NULL;
}



static 	int 	_SStrJ_DirUp(char * path)
{
	int 	i, length, flag;
	char * 	pPos;
	
	if(!path || (*path == '\0')){
		return -1;
	}
	
	/* Check the Tail / */
	length	= strlen(path)-1;
	pPos 	= path+length;
	_StrJ_Tail_Delimit(i, length, pPos, flag);
	if(length == 0){
		path[0] = '/';	path[1] = '\0';
		return 0;
	}
	
	*(pPos+1)= '\0';
	/* Check the Prev / */
	pPos = strrchr(path, '/');
	if((pPos == path) || (pPos == NULL)){
		pPos = strrchr(path, '\\');
	}
	if((pPos == path) || (pPos == NULL)){
		path[0] = '/';	path[1] = '\0';
		return 0;
	}
	else{
		*(pPos+1) = '\0';

		/* Check the Tail / */
		length 	= strlen(path)-1;
		pPos 	= path+length;
		_StrJ_Tail_Delimit(i, length, pPos, flag);
		if(length == 0){
			path[0] = '/';	path[1] = '\0';
			return 0;
		}
		*(pPos+2)= '\0';
	}
	return 0;
}


int 	SStrJ_Avail(char * name){
	if(name){
		if(	(_SStrJ_Head(name) == 0) && (_SStrJ_iLL(name) == 0)){
			return 0;
		}
	}
	return -1;
}


int 	SStrJ_Path(char * path, char * curr)
{
	int 	i, length, flag;
	int 	segLen, count;
	char *	pPos;
	char * 	pChk;
	
	char 	strSeg[S_APP_MAX_PATH+1];
	char 	strChg[S_APP_MAX_PATH+1];
	
	
	if(!path || (*path == '\0') || !curr)
		return -1;

	/* Prepare */
	length = strlen(curr);
	if(length >= S_APP_MAX_PATH)
		return -1;
	
	/* Filter the String */
	if(_SStrJ_iLL(path) == -1){
		SYS_TRACE(_gTraceLvl_Gears, TRACELVL_ERROR, "Path Seg Parse:[%s] Invalid.\n", path);
		return -1;
	}
	
	/* Check the Leading / */
	length 	= strlen(path);
	_StrJ_Head_Delimit(i, length, path, flag);
	if(length == 0){
		curr[0] = '/';	curr[1] = '\0';
		return 0;
	}

	/* Init the Change path */
	if(flag == 1){
		strChg[0] = '/'; strChg[1] = '\0';
	}
	else{
		length = strlen(curr);
		SYS_MEMCPY(strChg,curr, length);
		strChg[length] = '\0';
	}
	
	/* Go Through all the Segment */
	count = 0; flag = 1;
	while(flag == 1){
		strSeg[0] = '\0';
		pPos = _SStrJ_Seg(path, &segLen);
		
		if(segLen <= 0){
			flag = 0;
			break;
		}
		if(pPos == NULL){
			if(segLen == 0){
				/* '\\' Or '/' */
				if(count == 0){ /* Let's Back to Root */
					strChg[0] = '/';
					strChg[1] = '\0';
				}
			}
			flag = 0;
		}

		/* Now pPos & segLen */
		SYS_MEMCPY(strSeg, pPos, segLen);
		strSeg[segLen] = '\0';
		SYS_TRACE(_gTraceLvl_Gears, TRACELVL_NORMAL, "Path Seg Parse:[%s].\n", strSeg);

		/* We Need Check the Seg if .. */
		pChk = strstr(strSeg, "..");
		if(pChk){
			if(segLen != 2){
				SYS_TRACE(_gTraceLvl_Gears, TRACELVL_ERROR, "Path Seg Parse:[%s] Invalid.\n", strSeg);
				return -1;
			}
			_SStrJ_DirUp(strChg);
		}
		else{
			pChk = strstr(strSeg, ".");
			if(pChk){
				if(segLen != 1){
					/* Copy the Seg */
					length = strlen(strChg);
					SYS_MEMCPY(strChg+length, strSeg, segLen);
					length += segLen;	strChg[length] = '/';
					length += 1;		strChg[length] = '\0';
				}
			}
			else{
				/* Copy the Seg */
				length = strlen(strChg);
				SYS_MEMCPY(strChg+length, strSeg, segLen);
				length += segLen;	strChg[length] = '/';
				length += 1;		strChg[length] = '\0';
			}
		}

		/* Update the Cursor */
		path = pPos + segLen;
		count+=1;
	}

	path = strChg;
	/* Check the Leading / */
	length=strlen(strChg);
	_StrJ_Head_Delimit(i, length, path, flag);
	if(length == 0){
		curr[0] = '/';	curr[1] = '\0';
	}
	else{
		SYS_MEMCPY(curr, path-1, length+1);
		curr[length+1]='\0';
	}
	return 0;
}

#if 	_TARGET_OS == _OS_GNU
#include <limits.h>
int 	SStrJ_S2Int(char * intStr)
{
    char 	*pEnd;
    long 	val;

	if(intStr){
		errno = 0;
		val = strtol(intStr, &pEnd, 10);
   		if((errno == ERANGE) || (val == LONG_MAX)){
			SYS_TRACE(_gTraceLvl_Gears, TRACELVL_ERROR, "Str Parse Int:[%s] Fail.\n", intStr);
            return -1;
   		}
		if(pEnd == intStr){
			SYS_TRACE(_gTraceLvl_Gears, TRACELVL_ERROR, "Str Parse Int:[%s] Fail.\n", intStr);
            return -1;
		}
		return (int)val;
	}
	return -1;
}


static 	char 		_gStrFilter_Param[]={
	' ', ','
};

static 	char * _SStrJ_Param_Delim(char ** ppParam)
{
	int 	i, count, flag;
	char 	* 	pPos;
	char 	* 	pPeek;
	char 	* 	pParam;

	count = _N_ARRAY(_gStrFilter_Param);
	pPos  = NULL;
	pParam= *ppParam;
	
	/* Trim the Head Delim */
	do{
		flag = 0; 
		/* We found an Parameter, Is it an ' '&' ', ' '&',' , ','&' ', ','&',' ? */
		for(i=0; i<count; i++){
			if(pParam[0] == _gStrFilter_Param[i]){
				*pParam = '\0';
				pParam += 1;
				flag = 1;
				break;
			}
		}
		
	}while(flag == 1);

	*ppParam = pParam;
	/* Peek the Next Delim */
	for(i=0; i<count; i++){
		pPeek = strchr(pParam, _gStrFilter_Param[i]);
		if(pPeek){
			if(pPos){
				if(pPos > pPeek){
					pPos = pPeek;
				}
			}else{
				pPos = pPeek;
			}
		}
	}
	/* Let's Trim It! */
	if(pPos){
		*pPos = '\0';
	}
	return pPos;
}

int 	SStrJ_Param(char * pParam, 	char ** aParam)
{
	int 	nParam, rParam;
	char 	* 	pPos;
	char 	* 	pSrc;

	nParam	= 0;
	rParam	= 0;
	pPos 	= NULL;
	if(pParam && aParam){
		pSrc  = pParam;
		do{
			pPos = _SStrJ_Param_Delim(&pSrc);
			if(pPos && (pPos != pSrc)){
				nParam += 1;
				if(rParam < S_APP_MAX_PARAM){
					aParam[rParam] = pSrc; 
					rParam += 1;
				}
				SYS_TRACE(_gTraceLvl_Gears, TRACELVL_ERROR, "Str Parse Param:[%d] - [%d]: %s.\n", 
					nParam,
					rParam,
					pSrc);
				/* Step to Next */
				pSrc = pPos + 1;
			}

		}while(pPos != NULL);

		/* Last Segment */
		if(*pSrc != '\0'){
			nParam += 1;
			if(rParam < S_APP_MAX_PARAM){
				aParam[rParam] = pSrc; 
				rParam += 1;
			}
			SYS_TRACE(_gTraceLvl_Gears, TRACELVL_ERROR, "Str Parse Param:[%d] - [%d]: %s.\n", 
				nParam,
				rParam,
				pSrc);
		}
	}
	

	return rParam;
}

#endif

